From dad79c9182e5615f6da35f6625bddb5ed368e39b Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Wed, 16 Sep 2015 00:29:38 +0200 Subject: [PATCH] Add support for multiple -p options to `cargo clean` --- src/bin/clean.rs | 18 +++++------ src/cargo/ops/cargo_clean.rs | 55 +++++++++++++++++---------------- tests/test_cargo_clean.rs | 59 +++++++++++++++++++++++++++++++++++- 3 files changed, 96 insertions(+), 36 deletions(-) diff --git a/src/bin/clean.rs b/src/bin/clean.rs index 18c6111e5..8aea04d35 100644 --- a/src/bin/clean.rs +++ b/src/bin/clean.rs @@ -6,7 +6,7 @@ use cargo::util::important_paths::{find_root_manifest_for_cwd}; #[derive(RustcDecodable)] struct Options { - flag_package: Option, + flag_package: Vec, flag_target: Option, flag_manifest_path: Option, flag_verbose: bool, @@ -21,13 +21,13 @@ Usage: cargo clean [options] Options: - -h, --help Print this message - -p SPEC, --package SPEC Package to clean artifacts for - --manifest-path PATH Path to the manifest to the package to clean - --target TRIPLE Target triple to clean output for (default all) - -v, --verbose Use verbose output - -q, --quiet No output printed to stdout - --color WHEN Coloring: auto, always, never + -h, --help Print this message + -p SPEC, --package SPEC ... Package to clean artifacts for + --manifest-path PATH Path to the manifest to the package to clean + --target TRIPLE Target triple to clean output for (default all) + -v, --verbose Use verbose output + -q, --quiet No output printed to stdout + --color WHEN Coloring: auto, always, never If the --package argument is given, then SPEC is a package id specification which indicates which package's artifacts should be cleaned out. If it is not @@ -43,7 +43,7 @@ pub fn execute(options: Options, config: &Config) -> CliResult> { let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path)); let opts = ops::CleanOptions { config: config, - spec: options.flag_package.as_ref().map(|s| &s[..]), + spec: &options.flag_package, target: options.flag_target.as_ref().map(|s| &s[..]), }; ops::clean(&root, &opts).map(|_| None).map_err(|err| { diff --git a/src/cargo/ops/cargo_clean.rs b/src/cargo/ops/cargo_clean.rs index c3bc26827..06542b364 100644 --- a/src/cargo/ops/cargo_clean.rs +++ b/src/cargo/ops/cargo_clean.rs @@ -9,7 +9,7 @@ use util::{CargoResult, human, ChainError, Config}; use ops::{self, Layout, Context, BuildConfig, Kind}; pub struct CleanOptions<'a> { - pub spec: Option<&'a str>, + pub spec: &'a [String], pub target: Option<&'a str>, pub config: &'a Config, } @@ -21,28 +21,19 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> { // If we have a spec, then we need to delete some packages, otherwise, just // remove the whole target directory and be done with it! - let spec = match opts.spec { - Some(spec) => spec, - None => return rm_rf(&target_dir), - }; + if opts.spec.len() == 0 { + return rm_rf(&target_dir); + } - // Load the lockfile (if one's available), and resolve spec to a pkgid + // Load the lockfile (if one's available) let lockfile = root.root().join("Cargo.lock"); let source_id = root.package_id().source_id(); let resolve = match try!(ops::load_lockfile(&lockfile, source_id)) { Some(resolve) => resolve, None => return Err(human("A Cargo.lock must exist before cleaning")) }; - let pkgid = try!(resolve.query(spec)); - - // Translate the PackageId to a Package - let pkg = { - let mut source = pkgid.source_id().load(opts.config); - try!(source.update()); - (try!(source.get(&[pkgid.clone()]))).into_iter().next().unwrap() - }; - // Create a compilation context to have access to information like target + // Create a compilation context to have access to information like target // filenames and such let srcs = SourceMap::new(); let pkgs = PackageSet::new(&[]); @@ -52,17 +43,29 @@ pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> { None, BuildConfig::default(), &profiles)); - // And finally, clean everything out! - for target in pkg.targets().iter() { - // TODO: `cargo clean --release` - let layout = Layout::new(opts.config, &root, opts.target, "debug"); - try!(rm_rf(&layout.fingerprint(&pkg))); - let profiles = [Profile::default_dev(), Profile::default_test()]; - for profile in profiles.iter() { - for filename in try!(cx.target_filenames(&pkg, target, profile, - Kind::Target)).iter() { - try!(rm_rf(&layout.dest().join(&filename))); - try!(rm_rf(&layout.deps().join(&filename))); + // resolve package specs and remove the corresponding packages + for spec in opts.spec { + let pkgid = try!(resolve.query(spec)); + + // Translate the PackageId to a Package + let pkg = { + let mut source = pkgid.source_id().load(opts.config); + try!(source.update()); + (try!(source.get(&[pkgid.clone()]))).into_iter().next().unwrap() + }; + + // And finally, clean everything out! + for target in pkg.targets().iter() { + // TODO: `cargo clean --release` + let layout = Layout::new(opts.config, &root, opts.target, "debug"); + try!(rm_rf(&layout.fingerprint(&pkg))); + let profiles = [Profile::default_dev(), Profile::default_test()]; + for profile in profiles.iter() { + for filename in try!(cx.target_filenames(&pkg, target, profile, + Kind::Target)).iter() { + try!(rm_rf(&layout.dest().join(&filename))); + try!(rm_rf(&layout.deps().join(&filename))); + } } } } diff --git a/tests/test_cargo_clean.rs b/tests/test_cargo_clean.rs index 9ccd8f731..4b2828a6e 100644 --- a/tests/test_cargo_clean.rs +++ b/tests/test_cargo_clean.rs @@ -1,5 +1,5 @@ use support::{project, execs, main_file, basic_bin_manifest}; -use hamcrest::{assert_that, existing_dir, is_not}; +use hamcrest::{assert_that, existing_dir, existing_file, is_not}; fn setup() { } @@ -30,3 +30,60 @@ test!(different_dir { execs().with_status(0).with_stdout("")); assert_that(&p.build_dir(), is_not(existing_dir())); }); + +test!(clean_multiple_packages { + let p = project("foo") + .file("Cargo.toml", r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies.d1] + path = "d1" + [dependencies.d2] + path = "d2" + + [[bin]] + name = "foo" + "#) + .file("src/foo.rs", &main_file(r#""i am foo""#, &[])) + .file("d1/Cargo.toml", r#" + [package] + name = "d1" + version = "0.0.1" + authors = [] + + [[bin]] + name = "d1" + "#) + .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }") + .file("d2/Cargo.toml", r#" + [package] + name = "d2" + version = "0.0.1" + authors = [] + + [[bin]] + name = "d2" + "#) + .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }"); + p.build(); + + assert_that(p.cargo_process("build").arg("-p").arg("d1").arg("-p").arg("d2") + .arg("-p").arg("foo"), + execs().with_status(0)); + + assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.build_dir().join("debug").join("deps").join("d1"), existing_file()); + assert_that(&p.build_dir().join("debug").join("deps").join("d2"), existing_file()); + + assert_that(p.cargo("clean").arg("-p").arg("d1").arg("-p").arg("d2") + .cwd(&p.root().join("src")), + execs().with_status(0).with_stdout("")); + assert_that(&p.bin("foo"), existing_file()); + assert_that(&p.build_dir().join("debug").join("deps").join("d1"), + is_not(existing_file())); + assert_that(&p.build_dir().join("debug").join("deps").join("d2"), + is_not(existing_file())); +}); -- 2.30.2